import win32com.client
import pythoncom
import json


class InventorParser:
    def __init__(self):
        self.inventor_app = None
        self.part_doc = None
        self.assembly_doc = None

    def start_inventor(self):
        """启动Inventor应用程序"""
        try:
            self.inventor_app = win32com.client.Dispatch("Inventor.Application")
            self.inventor_app.Visible = True  # 可见模式（调试时建议开启）
            print("Inventor启动成功，版本:", self.inventor_app.SoftwareVersion)
            return True
        except Exception as e:
            print("Inventor启动失败:", str(e))
            return False

    def open_file(self, file_path):
        """打开Inventor文件（支持.ipt/.iam）"""
        if not self.inventor_app:
            print("未检测到Inventor进程")
            return None

        try:
            # 获取文档对象
            doc = self.inventor_app.Documents.Open(file_path)
            if doc.DocumentType == 12290:  # kPartDocumentObject
                self.part_doc = doc
                print(f"已打开零件文件: {file_path}")
                return self._parse_part()
            elif doc.DocumentType == 12291:  # kAssemblyDocumentObject
                self.assembly_doc = doc
                print(f"已打开装配文件: {file_path}")
                return self._parse_assembly()
            else:
                print("不支持的文件类型")
                return None
        except Exception as e:
            import traceback
            print("详细错误信息:\n", traceback.format_exc())
            return None

    def _parse_part(self):
        """解析零件文件（.ipt）"""
        part_data = {
            "parameters": {},
            "features": [],
            "bodies": []
        }

        # 提取参数
        params = self.part_doc.ComponentDefinition.Parameters
        for param in params:
            part_data["parameters"][param.Name] = {
                "value": param.Value,
                "unit": param.Units,
                "comment": param.Comment
            }

        # 提取特征树
        features = self.part_doc.ComponentDefinition.Features
        for feature in features:
            feat_info = {
                "name": feature.Name,
                "type": feature.Type,
                "parameters": {}
            }
            # 提取特征参数（以拉伸特征为例）
            if feature.Type == 12296:  # kExtrudeFeatureObject
                feat_info["parameters"]["profile"] = feature.Profile.Name
                feat_info["parameters"]["distance"] = feature.Depth.Value
            part_data["features"].append(feat_info)

        # 提取几何体信息
        bodies = self.part_doc.ComponentDefinition.SurfaceBodies
        for body in bodies:
            try:
                body_info = {
                    "volume": body.Volume if hasattr(body, "Volume") else None,
                    "area": body.Area if hasattr(body, "Area") else None,
                    "face_count": body.Faces.Count
                }
                part_data["bodies"].append(body_info)
            except Exception as e:
                print(f"几何体属性提取失败: {str(e)}")
                continue

        return part_data

    def _parse_assembly(self):
        """解析装配文件（.iam）"""
        assembly_data = {
            "components": [],
            "constraints": []
        }

        # 提取组件信息
        occurrences = self.assembly_doc.ComponentDefinition.Occurrences
        for occ in occurrences:
            component = {
                "name": occ.Name,
                "file": occ.ReferencedDocumentDescriptor.FullDocumentName,
                "position": []
            }
            # 检查 Transformation 属性是否存在
            if hasattr(occ, "Transformation"):
                try:
                    # 兼容不同版本API的坐标获取方式
                    translation = [occ.Transformation.Translation.X,
                                   occ.Transformation.Translation.Y,
                                   occ.Transformation.Translation.Z]
                    component["position"] = translation
                except AttributeError:
                    # 旧版本API可能需要使用 get_Translation
                    try:
                        translation = [occ.Transformation.get_Translation(i) for i in range(3)]
                        component["position"] = translation
                    except Exception as e:
                        print(f"组件 {occ.Name} 位置获取失败: {str(e)}")
            assembly_data["components"].append(component)

        # 提取装配约束
        constraints = self.assembly_doc.ComponentDefinition.Constraints
        for constr in constraints:
            constr_info = {
                "type": constr.Type,
                "components": [occ.Name for occ in constr.Occurrences],
                "offset": constr.Offset.Value if hasattr(constr, "Offset") else None
            }
            assembly_data["constraints"].append(constr_info)

        return assembly_data

    def close(self):
        """关闭Inventor并释放资源"""
        if self.inventor_app:
            self.inventor_app.Quit()
            self.inventor_app = None
            print("Inventor已关闭")


# ---------------------- 使用示例 ----------------------
if __name__ == "__main__":
    parser = InventorParser()
    if parser.start_inventor():
        # 示例文件路径（替换为实际路径）
        part_file = r"F:\学习文件\毕业设计\建模文件\刚轮.ipt"
        assembly_file = r"F:\学习文件\毕业设计\建模文件\装配3\设计加速器\轴承1.iam"

        # 解析零件文件
        part_data = parser.open_file(part_file)
        if part_data:
            # 确保所有值都是 JSON 可序列化的
            def serialize(obj):
                if isinstance(obj, (int, float, str, bool, type(None))):
                    return obj
                elif isinstance(obj, list):
                    return [serialize(item) for item in obj]
                elif isinstance(obj, dict):
                    return {key: serialize(value) for key, value in obj.items()}
                else:
                    return str(obj)

            part_data = serialize(part_data)
            with open("part_output.json", "w") as f:
                json.dump(part_data, f, indent=2)
            print("零件数据已保存至 part_output.json")

        # 解析装配文件
        assembly_data = parser.open_file(assembly_file)
        if assembly_data:
            assembly_data = serialize(assembly_data)
            with open("assembly_output.json", "w") as f:
                json.dump(assembly_data, f, indent=2)
            print("装配数据已保存至 assembly_output.json")

        parser.close()


# 示例输出结构（适合模型输入）
"""
零件特征解析结果:
{
    "total_features": 5,
    "feature_list": [
        {
            "name": "Hole1",
            "type": "Hole",
            "is_suppressed": false,
            "parameters": {
                "diameter": 10.0,
                "depth": 15.0
            },
            "coordinates": [50.0, 50.0, 0.0]  # 孔中心坐标
        },
        {
            "name": "Extrude1",
            "type": "Extrude",
            "parameters": {
                "depth": 20.0,
                "symmetric": false
            },
            "coordinates": [0.0, 0.0, 1.0]  # 拉伸方向向量（Z轴正方向）
        }
    ]
}

装配约束解析结果:
{
    "component_list": [
        {
            "name": "BasePlate:1",
            "position": [0.0, 0.0, 0.0],
            "is_ground": true
        },
        {
            "name": "Bolt:1",
            "position": [50.0, 50.0, 20.0],
            "is_ground": false
        }
    ],
    "constraint_list": [
        {
            "type": "Mate",
            "part1": "BasePlate:1",
            "part2": "Bolt:1",
            "value": null,
            "unit": ""
        },
        {
            "type": "Distance",
            "part1": "BasePlate:1",
            "part2": "Bracket:1",
            "value": 30.0,
            "unit": "mm"
        }
    ]
}
"""